home *** CD-ROM | disk | FTP | other *** search
/ PC User 2003 January / Disc 1 / PCU0103CD1.iso / entertn / demos / files / aomtrial.exe / AOM / AI / SCN07P7.XS < prev    next >
Encoding:
Text File  |  2002-08-30  |  21.9 KB  |  619 lines

  1. //==============================================================================
  2. // Scn07p7: AI Scenario Script for scenario 7 player 2
  3. //==============================================================================
  4. /*
  5.    AI owner:  Mike Kidd
  6.    Scenario owner: Jeff Brown
  7.  
  8.    Overview:
  9.    This CP occupies the east edge of the map.  His role is to maintain an economy,
  10.    and use that to build a navy with which he will attempt to control the water.
  11.  
  12.    The economy consists of a fishing plan, farming, woodcutting, and gold mining.
  13.  
  14.    This CP will not age up (stays in 3rd age), will not use god powers, and will
  15.    not research any upgrades.  It will maintain a gatherer and fishing population,
  16.    and will train warships as quickly as it can, up to a hard limit that depends
  17.    on difficulty level.
  18.  
  19.    7/31/2002:  Added a wakeup() function to make it start later.  Reduced starting
  20.    vills to zero.  Changed attack logic to attack at start of time interval if 
  21.    attack group size is >= 1/2 max.
  22.  
  23. */
  24.  
  25. include "scn lib.xs";
  26.  
  27.  
  28.  
  29. // Cinematic blocks
  30. const string cbCenter = "8052";
  31. const string cbDock = "8053";
  32. const string cbDefendPoint = "8516";
  33. const string cbAttackGather = "8517";
  34. const string cbWaypointLand = "8518";
  35. const string cbWaypointWater = "8519";
  36. const string cbIsland = "8520";
  37. const string cbNorthBeach = "8521";
  38. const string cbEastBeach = "8522";
  39. const string cbSouthBeach = "8523";
  40. const string cbP7TC = "3662";
  41.  
  42.  
  43. int   maxVills = 5;        // Will scale with difficulty
  44. int   maxFishBoats = 3;    // Including one to scout
  45. int   reserveSize = 15;
  46. int   armyTotal = 30;
  47. float goldPercent = 0.30;
  48. float woodPercent = 0.60;
  49. float foodPercent = 0.1;
  50.  
  51. int   attackRouteNorth = -1;
  52. int   attackRouteEast = -1;
  53. int   attackRouteSouth = -1;
  54. int   attackRouteIsland = -1;
  55.  
  56. int   maxWarships = 1;
  57. int   navalMaintain = -1;  // Naval unit maintain plan
  58. int   transportMaintain = -1;
  59.  
  60. int   gathererTypeID = -1;
  61. int   fishGatherer = -1;
  62.  
  63. int   mainBase = -1;
  64. float mainRadius = 60.0;
  65.  
  66. int   startTime = -1;    // Time of wakeup call
  67. int   nextNavalAttack = 240000;      // Absolute limit on attack start
  68. int   minNavalAttackInterval = 480000; 
  69. int   maxNavalAttackInterval = 540000;  
  70.  
  71. int   nextLandAttack = 1200000;    // 20 minutes
  72. int   landAttackInterval = 1200000;
  73. int   totalArmySize = 15;
  74. float landAttackSize = 2;
  75. int   maxLandAttackSize = 6;
  76. float armySizeMultiplier = 1.5;
  77.  
  78. int   mainlandAreaGroup = -1;
  79. int   islandAreaGroup = -1;
  80.  
  81. int   defendPlan = -1;
  82. int   reservePlan = -1;
  83.  
  84.  
  85. void wakeup(int parm=-1)      // AI FUNC trigger to tell CP to start
  86. {
  87.    aiEcho("Wakeup firing at "+timeString());
  88.  
  89.    static bool alreadyRun = false;  // Prevents multiple calls from taking effect
  90.    if (alreadyRun == true)
  91.       return;
  92.    alreadyRun = true;
  93.  
  94.    startTime = xsGetTime();
  95.    nextNavalAttack = nextNavalAttack + startTime;
  96.    nextLandAttack = nextLandAttack + startTime;
  97.  
  98.    // Create villager maintain plan
  99.    createSimpleMaintainPlan(gathererTypeID, maxVills, true, mainBase);
  100.    // Create warship maintain plan  cUnitTypeFishingShipGreek  cUnitTypeArcherShip
  101.    navalMaintain = maintainUnit(cUnitTypeTrireme, (totalArmySize/3), kbGetBlockPosition(cbWaypointWater), 1);
  102.    transportMaintain = maintainUnit(cUnitTypeTransportShipGreek, 2, kbGetBlockPosition(cbDock), 1);
  103.    aiPlanSetDesiredPriority(transportMaintain, 80);
  104.    aiPlanSetDesiredPriority(navalMaintain, 60);
  105.    
  106.    // Create toxote maintain plan
  107.    maintainUnit(cUnitTypeToxotes, totalArmySize, kbGetBlockPosition(cbP7TC), mainBase);
  108.  
  109.    // Define attack routes
  110.    attackRouteNorth = attackRoute("Attack Route North", cbWaypointLand, cbWaypointWater, cbNorthBeach);
  111.    attackRouteEast = attackRoute("Attack Route East", cbWaypointLand, cbWaypointWater, cbEastBeach);
  112.    attackRouteSouth = attackRoute("Attack Route South", cbWaypointLand, cbWaypointWater, cbSouthBeach);
  113.    attackRouteIsland = attackRoute("Attack Route Island", cbWaypointLand, cbWaypointWater, cbIsland);
  114.  
  115.    // Init low-priority defend plan to manage spare units
  116.    defendPlan =aiPlanCreate("Defend Plan", cPlanDefend);
  117.    if (defendPlan >= 0)
  118.    {
  119.       aiPlanAddUnitType(defendPlan, cUnitTypeToxotes, 0, 200, 200);    // All unassigned mil units
  120.       aiPlanSetDesiredPriority(defendPlan, 10);                       // Way low, below scouting and attack
  121.       aiPlanSetVariableVector(defendPlan, cDefendPlanDefendPoint, 0, kbGetBlockPosition(cbP7TC));
  122.       aiPlanSetVariableFloat(defendPlan, cDefendPlanEngageRange, 0, 40);
  123.  
  124.       aiPlanSetVariableFloat(defendPlan, cDefendPlanGatherDistance, 0, 15.0);
  125.       aiPlanSetInitialPosition(defendPlan, kbGetBlockPosition(cbP7TC));
  126.       aiPlanSetUnitStance(defendPlan, cUnitStanceDefensive);
  127.  
  128.       aiPlanSetVariableBool(defendPlan, cDefendPlanPatrol, 0, false);
  129.  
  130.       aiPlanSetVariableInt(defendPlan, cDefendPlanRefreshFrequency, 0, 5);
  131.       aiPlanSetNumberVariableValues(defendPlan, cDefendPlanAttackTypeID, 2, true);
  132.       aiPlanSetVariableInt(defendPlan, cDefendPlanAttackTypeID, 0, cUnitTypeUnit);
  133.       aiPlanSetVariableInt(defendPlan, cDefendPlanAttackTypeID, 1, cUnitTypeBuilding);
  134.       
  135.       aiPlanSetActive(defendPlan); 
  136.       aiEcho("Creating defend plan");
  137.    }
  138.  
  139.    // Higher-priority defend plan to reserve units for final push
  140.    reservePlan =aiPlanCreate("Reserve Plan", cPlanDefend);
  141.    if (reservePlan >= 0)
  142.    {
  143.       aiPlanAddUnitType(reservePlan, cUnitTypeMilitary, 0, totalArmySize/3, totalArmySize/3);   
  144.       aiPlanSetDesiredPriority(reservePlan, 30);                       // Higher than other defend plans
  145.       aiPlanSetVariableVector(reservePlan, cDefendPlanDefendPoint, 0, kbGetBlockPosition(cbP7TC));
  146.       aiPlanSetVariableFloat(reservePlan, cDefendPlanEngageRange, 0, 10);
  147.  
  148.       aiPlanSetVariableFloat(reservePlan, cDefendPlanGatherDistance, 0, 10.0);
  149.       aiPlanSetInitialPosition(reservePlan, kbGetBlockPosition(cbP7TC));
  150.       aiPlanSetUnitStance(reservePlan, cUnitStanceDefensive);
  151.  
  152.       aiPlanSetVariableBool(reservePlan, cDefendPlanPatrol, 0, false);
  153.  
  154.       aiPlanSetVariableInt(reservePlan, cDefendPlanRefreshFrequency, 0, 5);
  155.       aiPlanSetNumberVariableValues(reservePlan, cDefendPlanAttackTypeID, 2, true);
  156.       aiPlanSetVariableInt(reservePlan, cDefendPlanAttackTypeID, 0, cUnitTypeUnit);
  157.       aiPlanSetVariableInt(reservePlan, cDefendPlanAttackTypeID, 1, cUnitTypeBuilding);
  158.       
  159.       aiPlanSetActive(reservePlan); 
  160.       aiEcho("Creating reserve defend plan");
  161.    }
  162.  
  163.  
  164.    xsEnableRule("navalAttackGenerator");
  165.    xsEnableRule("landAttackGenerator");
  166. }
  167.  
  168.  
  169.  
  170. void initMainBase()
  171. {
  172.    // Nuke bases, add one base to rule them all
  173.    kbBaseDestroyAll(cMyID);
  174.  
  175.    mainBase = kbBaseCreate(cMyID, "Base "+kbBaseGetNextID(), kbGetBlockPosition(cbCenter), mainRadius);
  176.    if (mainBase < 0)
  177.       aiEcho("***** Main base creation failed. *****");
  178.  
  179.    vector baseFront=xsVectorNormalize(kbGetMapCenter()-kbGetBlockPosition(cbCenter));     // Set front
  180.    kbBaseSetFrontVector(cMyID, mainBase, baseFront);                 
  181.    kbBaseSetMaximumResourceDistance(cMyID, mainBase, mainRadius+20.0);                    // Gather up to 20m beyond base perimeter
  182.    kbBaseSetMain(cMyID, mainBase, true);     // Make this the main base
  183.  
  184.    // Add the buildings
  185.    int buildingQuery = -1;
  186.    int count = 0;
  187.    buildingQuery = kbUnitQueryCreate("Building Query");     // All buildings in the base
  188.    configQuery(buildingQuery, cUnitTypeBuilding, -1, cUnitStateAliveOrBuilding, cMyID, kbGetBlockPosition(cbCenter), false, mainRadius);
  189.    kbUnitQueryResetResults(buildingQuery);
  190.    count = kbUnitQueryExecute(buildingQuery);
  191.  
  192.    int i = 0;
  193.    int buildingID = -1;
  194.    for (i=0; < count)
  195.    {
  196.       buildingID = kbUnitQueryGetResult(buildingQuery, i);
  197.       // Add it to the base
  198.       kbBaseAddUnit( cMyID, mainBase, buildingID );
  199.    }
  200. }
  201.  
  202.  
  203. void initEcon()
  204. {
  205.    aiSetAttackResponseDistance(20.0);   // Kill escrows
  206.    kbEscrowSetPercentage( cEconomyEscrowID, cAllResources, 0.0);
  207.    kbEscrowSetPercentage( cMilitaryEscrowID, cAllResources, 0.0);
  208.    kbEscrowAllocateCurrentResources();
  209.  
  210.    aiSetAutoGatherEscrowID(cRootEscrowID);
  211.    aiSetAutoFarmEscrowID(cRootEscrowID);
  212.    gathererTypeID = kbTechTreeGetUnitIDTypeByFunctionIndex(cUnitFunctionGatherer,0);
  213.  
  214.    
  215.    int herdPlanID=aiPlanCreate("GatherHerdable Plan", cPlanHerd);
  216.    if (herdPlanID >= 0)
  217.    {
  218.       aiPlanAddUnitType(herdPlanID, cUnitTypeHerdable, 0, 100, 100);
  219.       aiPlanSetVariableInt(herdPlanID, cHerdPlanBuildingTypeID, 0, cUnitTypeSettlementLevel1);
  220.       aiPlanSetActive(herdPlanID);
  221.    }
  222.  
  223.    aiSetResourceGathererPercentageWeight(cRGPScript, 1);
  224.    aiSetResourceGathererPercentageWeight(cRGPCost, 0);
  225.  
  226.    kbSetAICostWeight(cResourceFood, 1.0);
  227.    kbSetAICostWeight(cResourceWood, 0.7);
  228.    kbSetAICostWeight(cResourceGold, 0.8);
  229.    kbSetAICostWeight(cResourceFavor, 7.0);
  230.  
  231.    aiSetResourceGathererPercentage(cResourceFood, foodPercent, false, cRGPScript);
  232.    aiSetResourceGathererPercentage(cResourceWood, woodPercent, false, cRGPScript);
  233.    aiSetResourceGathererPercentage(cResourceGold, goldPercent, false, cRGPScript);
  234.    aiSetResourceGathererPercentage(cResourceFavor, 0.0, false, cRGPScript);
  235.    aiNormalizeResourceGathererPercentages(cRGPScript);
  236.  
  237.    //bool aiSetResourceBreakdown( int resourceTypeID, int resourceSubTypeID, int numberPlans, int planPriority, float percentage, int baseID )
  238. //    aiSetResourceBreakdown(cResourceFood, cAIResourceSubTypeEasy, numFoodEasyPlans, 50, 1.0, gMainBaseID);
  239. //   aiSetResourceBreakdown(cResourceFood, cAIResourceSubTypeHuntAggressive, numFoodHuntAggressivePlans, 100, 1.0, gMainBaseID);
  240.    aiSetResourceBreakdown(cResourceFood, cAIResourceSubTypeFish, 1, 50, 1.0, mainBase);
  241.    aiSetResourceBreakdown(cResourceFood, cAIResourceSubTypeFarm, 1, 50, 1.0, mainBase);
  242.    aiSetResourceBreakdown(cResourceWood, cAIResourceSubTypeEasy, 1, 50, 1.0, mainBase);
  243.     aiSetResourceBreakdown(cResourceGold, cAIResourceSubTypeEasy, 1, 50, 1.0, mainBase);
  244. //   aiSetResourceBreakdown(cResourceFavor, cAIResourceSubTypeEasy, numFavorPlans, 50, 1.0, gMainBaseID);
  245. }
  246.  
  247.  
  248.  
  249. void attack()
  250. {
  251.  
  252.    int   attackID=aiPlanCreate("Boat Attack "+timeString()+"  ", cPlanAttack);
  253.    if (attackID < 0)
  254.    {
  255.       return;
  256.    }
  257.  
  258.    if (aiPlanSetVariableInt(attackID, cAttackPlanPlayerID, 0, 1) == false)
  259.    {
  260.       return;
  261.    }
  262.  
  263.    if (aiPlanSetNumberVariableValues(attackID, cAttackPlanTargetTypeID, 2, true) == false)
  264.    {
  265.       return;
  266.    }
  267.  
  268.    // add "unit" and "building" to attack list
  269.    aiPlanSetVariableInt(attackID, cAttackPlanTargetTypeID, 0, cUnitTypeUnit);
  270.    aiPlanSetVariableInt(attackID, cAttackPlanTargetTypeID, 1, cUnitTypeBuilding);
  271.  
  272.  
  273.  
  274.    aiPlanSetVariableVector(attackID, cAttackPlanGatherPoint, 0, kbGetBlockPosition(cbWaypointWater));
  275.    aiPlanSetVariableFloat(attackID, cAttackPlanGatherDistance, 0, 30.0);
  276.  
  277.    aiPlanAddUnitType(attackID, cUnitTypeTrireme, 1, maxWarships, maxWarships);
  278.  
  279.  
  280.    aiPlanSetInitialPosition(attackID, kbGetBlockPosition(cbWaypointWater));
  281.    aiPlanSetRequiresAllNeedUnits(attackID, true);
  282.    aiPlanSetActive(attackID);
  283.    aiEcho("Activating attack plan "+attackID);
  284. //   if (lastAttackPlan >= 0)
  285. //      aiPlanDestroy(lastAttackPlan);   // free up last set of units?
  286. //   lastAttackPlan = attackID; // update the global var
  287. }
  288.  
  289.  
  290. void landAttack()
  291. {
  292.    static int islandQuery = -1;
  293.    aiEcho("Doing land attack with "+landAttackSize+" units.");
  294.  
  295.    if (islandQuery < 0)
  296.    {
  297.       islandQuery = kbUnitQueryCreate("Island query");
  298.       configQuery(islandQuery, cUnitTypeUnit, -1, cUnitStateAlive, 1, kbGetBlockPosition(cbIsland), false, 20);   // P1 units on island
  299.    }
  300.    kbUnitQueryResetResults(islandQuery);
  301.    
  302.    bool islandValid = false;
  303.    if (kbUnitQueryExecute(islandQuery) > 0)
  304.    {
  305.       aiEcho("Targets exist on island");
  306.       islandValid = true;
  307.    }
  308.    else
  309.    {
  310.       islandValid = false;
  311.       aiEcho("No targets on island");
  312.    }
  313.  
  314.    int randVal = -1;
  315.    if (islandValid == true)
  316.       randVal = aiRandInt(4);       // Used for picking attack route, destination (below)
  317.    else
  318.       randVal = aiRandInt(3);
  319.  
  320.    int   attackID=aiPlanCreate("Land Attack on target "+randVal+" at "+timeString()+"  ", cPlanAttack);
  321.    if (attackID < 0)
  322.    {
  323.       return;
  324.    }
  325.    if (aiPlanSetVariableInt(attackID, cAttackPlanPlayerID, 0, 1) == false)
  326.    {
  327.       return;
  328.    }
  329.    if (aiPlanSetNumberVariableValues(attackID, cAttackPlanTargetTypeID, 1, true) == false)
  330.    {
  331.       return;
  332.    }
  333.    // add "unit" and "building" to attack list
  334.    aiPlanSetVariableInt(attackID, cAttackPlanTargetTypeID, 0, cUnitTypeUnit);
  335. //   aiPlanSetVariableInt(attackID, cAttackPlanTargetTypeID, 1, cUnitTypeBuilding);
  336.  
  337.    aiPlanSetVariableVector(attackID, cAttackPlanGatherPoint, 0, kbGetBlockPosition(cbWaypointLand));
  338.    aiPlanSetVariableFloat(attackID, cAttackPlanGatherDistance, 0, 30.0);
  339.  
  340.    aiPlanAddUnitType(attackID, cUnitTypeToxotes, 1, landAttackSize, landAttackSize);
  341.  
  342.    aiPlanSetInitialPosition(attackID, kbGetBlockPosition(cbWaypointLand));
  343.    aiPlanSetUnitStance(attackID, cUnitStanceAggressive);
  344.    aiPlanSetRequiresAllNeedUnits(attackID, true);
  345.  
  346.  
  347.    switch(randVal)   // Pick an attack route, continent destination.
  348.    {
  349.    case 0:        // North
  350.       {
  351.          // Specify continent 
  352.          aiPlanSetNumberVariableValues( attackID, cAttackPlanTargetAreaGroups,  1, true);  
  353.          aiPlanSetVariableInt(attackID, cAttackPlanTargetAreaGroups, 0, kbAreaGroupGetIDByPosition(kbGetBlockPosition(cbNorthBeach)));
  354.          aiPlanSetVariableInt(attackID, cAttackPlanAttackRouteID, 0, attackRouteNorth);
  355.          aiEcho("Attacking north beach.");
  356.          break;
  357.       }
  358.    case 1:        // East
  359.       {
  360.          // Specify continent 
  361.          aiPlanSetNumberVariableValues( attackID, cAttackPlanTargetAreaGroups,  1, true);  
  362.          aiPlanSetVariableInt(attackID, cAttackPlanTargetAreaGroups, 0, kbAreaGroupGetIDByPosition(kbGetBlockPosition(cbNorthBeach)));
  363.          aiPlanSetVariableInt(attackID, cAttackPlanAttackRouteID, 0, attackRouteEast);
  364.          aiEcho("Attacking east beach.");
  365.          break;
  366.       }
  367.    case 2:        // South
  368.       {
  369.          // Specify continent 
  370.          aiPlanSetNumberVariableValues( attackID, cAttackPlanTargetAreaGroups,  1, true);  
  371.          aiPlanSetVariableInt(attackID, cAttackPlanTargetAreaGroups, 0, kbAreaGroupGetIDByPosition(kbGetBlockPosition(cbNorthBeach)));
  372.          aiPlanSetVariableInt(attackID, cAttackPlanAttackRouteID, 0, attackRouteSouth);
  373.          aiEcho("Attacking south beach.");
  374.          break;
  375.       }
  376.    case 3:        // Island
  377.       {
  378.          // Specify continent 
  379.          aiPlanSetNumberVariableValues( attackID, cAttackPlanTargetAreaGroups,  1, true);  
  380.          aiPlanSetVariableInt(attackID, cAttackPlanTargetAreaGroups, 0, kbAreaGroupGetIDByPosition(kbGetBlockPosition(cbIsland)));
  381.          aiPlanSetVariableInt(attackID, cAttackPlanAttackRouteID, 0, attackRouteIsland);
  382.          aiEcho("Attacking island.");
  383.          break;
  384.       }
  385.    }
  386.  
  387.    aiPlanSetActive(attackID);
  388.    aiEcho("Activating attack plan "+attackID);
  389. }
  390.  
  391.  
  392. void main()
  393. {
  394.    aiEcho("Starting Scn07p7.xs");
  395.    aiRandSetSeed();
  396.    kbSetTownLocation(kbGetBlockPosition(cbCenter));
  397.    //Calculate some areas.
  398.    kbAreaCalculate(1200.0);
  399.  
  400.  
  401.    mainlandAreaGroup = kbAreaGroupGetIDByPosition(kbGetBlockPosition(cbNorthBeach));
  402.    islandAreaGroup = kbAreaGroupGetIDByPosition(kbGetBlockPosition(cbIsland));
  403.  
  404.    switch(aiGetWorldDifficulty())
  405.    {
  406.    case 0:
  407.       {
  408.          maxWarships = 1;
  409.          maxVills = 5;
  410.          nextNavalAttack = 10*60*1000;
  411.          minNavalAttackInterval = 6*60*1000;
  412.          maxNavalAttackInterval = 2 * minNavalAttackInterval;
  413.          nextLandAttack = 20*60*1000;
  414.          landAttackInterval = 20*60*1000;
  415.          landAttackSize = 2.0;
  416.          armySizeMultiplier = 1.5;
  417.          maxLandAttackSize = 6;
  418.          totalArmySize = 15;
  419.          break;
  420.       }
  421.    case 1:
  422.       {
  423.          maxWarships = 2;
  424.          maxVills = 6;
  425.          nextNavalAttack = 360000;      // Absolute limit on attack start
  426.          minNavalAttackInterval = 240000; 
  427.          maxNavalAttackInterval = 480000;  
  428.          nextLandAttack = 15*60*1000;
  429.          landAttackInterval = 13*60*1000;
  430.          landAttackSize = 3.0;
  431.          armySizeMultiplier = 1.5;
  432.          maxLandAttackSize = 8;
  433.          totalArmySize = 20;
  434.          break;
  435.       }
  436.    case 2:
  437.       {
  438.          maxWarships = 4;
  439.          maxVills = 10;
  440.          nextNavalAttack = 360000;      // Absolute limit on attack start
  441.          minNavalAttackInterval = 180000; 
  442.          maxNavalAttackInterval = 300000;  
  443.          nextLandAttack = 13*60*1000;
  444.          landAttackInterval = 10*60*1000;
  445.          landAttackSize = 5.0;
  446.          armySizeMultiplier = 1.5;
  447.          maxLandAttackSize = 12;
  448.          totalArmySize = 30;
  449.          break;
  450.       }
  451.    case 3:
  452.       {
  453.          maxWarships = 8;
  454.          maxVills = 20;
  455.          nextNavalAttack = 240000;      // Absolute limit on attack start
  456.          minNavalAttackInterval = 120000; 
  457.          maxNavalAttackInterval = 240000;  
  458.          nextLandAttack = 8*60*1000;
  459.          landAttackInterval = 6*60*1000;
  460.          landAttackSize = 8.0;
  461.          armySizeMultiplier = 1.4;
  462.          maxLandAttackSize = 20;
  463.          totalArmySize = 40;
  464.          break;
  465.       }
  466.    }
  467.  
  468.    initMainBase();    // Destroy all auto-bases, make one manual base for everything
  469.    initEcon();
  470.  
  471. }
  472.  
  473.  
  474.  
  475. rule killNavalActivity
  476.    minInterval 5
  477.    active
  478. {
  479.    if (aiGetWorldDifficulty() > 1)  
  480.    {
  481.       xsDisableSelf();
  482.       return;  // Quit if hard or nightmare
  483.    }
  484.  
  485.    if (kbUnitCount(cMyID, cUnitTypeDock, cUnitStateAlive) < 1)
  486.    {
  487.       aiEcho("Dock destroyed, stopping naval activity.");
  488.       aiPlanDestroy(navalMaintain);
  489.       aiPlanDestroy(transportMaintain);
  490.       xsDisableRule("navalAttackGenerator");
  491.       xsDisableRule("landAttackGenerator");
  492.       xsDisableSelf();
  493.    }
  494. }
  495.  
  496. rule navalAttackGenerator
  497.    minInterval 15
  498.    inactive
  499. {
  500.    if (xsGetTime() < nextNavalAttack)
  501.       return;
  502.  
  503.    int warships = 0;
  504.    warships = kbUnitCount(cMyID, cUnitTypeTrireme, cUnitStateAlive);
  505.  
  506.    if (warships < 1)
  507.       return;
  508.  
  509.    // If we're under time limit,  and below max/2, do nothing.
  510.    if (xsGetTime() < (nextNavalAttack + (maxNavalAttackInterval-minNavalAttackInterval) ))
  511.       if (warships < (maxWarships/2))
  512.          return;
  513.  
  514.    // If we're here, we're either out of time, or at max/2 ship pop and at an OK time.
  515.    attack();
  516.    nextNavalAttack = xsGetTime() + minNavalAttackInterval;
  517.    aiEcho("Doing boat attack with "+warships+" boats.");
  518.  
  519. }
  520.  
  521. rule landAttackGenerator
  522.    minInterval 13
  523.    inactive
  524. {
  525.    if (xsGetTime() < nextLandAttack)
  526.       return;
  527.  
  528.    landAttack();
  529.  
  530.    nextLandAttack = xsGetTime() + landAttackInterval;
  531.    landAttackSize = landAttackSize * armySizeMultiplier;
  532.    if (landAttackSize > maxLandAttackSize)
  533.       landAttackSize = maxLandAttackSize;
  534.  
  535. }
  536. //==============================================================================
  537. // RULE: fishing
  538. //==============================================================================
  539. rule fishing
  540.    minInterval 30
  541.    active
  542. {
  543.  
  544.     //-- Get the closest water area.  if there isn't one, we can't fish.
  545.     static int areaID = -1;
  546.     if(areaID == -1)
  547.         areaID = kbAreaGetClosetArea(kbGetBlockPosition(cbCenter), cAreaTypeWater);
  548.  
  549. //    if( kbSetupForResource(mainBase, cResourceWood, 25.0, 600) == false)
  550. //      return;
  551.    
  552.     //-- get our fish gatherer.
  553.     fishGatherer = kbTechTreeGetUnitIDTypeByFunctionIndex(cUnitFunctionFish,0);
  554.  
  555.     //-- Create the fish plan.
  556.     int fishPlanID=aiPlanCreate("FishPlan", cPlanFish);
  557.     if (fishPlanID >= 0)
  558.     {
  559.         aiEcho("Starting up the fishing plan.  Will fish when I find fish.");
  560.       aiPlanSetDesiredPriority(fishPlanID, 70);
  561.         aiPlanSetVariableVector(fishPlanID, cFishPlanLandPoint, 0, kbGetBlockPosition(cbCenter));
  562.         //-- If you don't explicitly set the water point, the plan will find one for you.
  563.         aiPlanSetVariableBool(fishPlanID, cFishPlanAutoTrainBoats, 0, false);   // I'm going to have a  maintain plan for fishing + scouting combined
  564.         aiPlanSetEscrowID(fishPlanID, cRootEscrowID);
  565.  
  566.         aiPlanAddUnitType(fishPlanID, fishGatherer, 1, maxFishBoats-1, maxFishBoats-1);
  567.         aiPlanSetActive(fishPlanID);
  568.     }
  569.  
  570. /*
  571.    //-- Build a dock in water, so we can scout.
  572.    int buildDock = aiPlanCreate("BuildDock", cPlanBuild);
  573.    if(buildDock >= 0)
  574.    {
  575.       aiEcho("Building dock for scouting.");
  576.       //BP Type and Priority.
  577.       aiPlanSetVariableInt(buildDock, cBuildPlanBuildingTypeID, 0, cUnitTypeDock);
  578.       aiPlanSetDesiredPriority(buildDock, 100);
  579.       aiPlanSetVariableVector(buildDock, cBuildPlanDockPlacementPoint, 0, kbBaseGetLocation(cMyID, gMainBaseID));
  580.       aiPlanSetVariableVector(buildDock, cBuildPlanDockPlacementPoint, 1, kbAreaGetCenter(areaID));
  581.       aiPlanAddUnitType(buildDock, kbTechTreeGetUnitIDTypeByFunctionIndex(cUnitFunctionBuilder, 0), 1, 1, 1);
  582.       aiPlanSetEscrowID(buildDock, cEconomyEscrowID);
  583.       aiPlanSetActive(buildDock);
  584.    }
  585. */
  586.  
  587.    createSimpleMaintainPlan(fishGatherer, maxFishBoats, true, mainBase);
  588.  
  589.    // Add a fish boat plan
  590.    int exploreWaterID = aiPlanCreate("Water Explore", cPlanExplore);
  591.    if(exploreWaterID >= 0)
  592.    {
  593.  
  594.       aiPlanSetVariableFloat( exploreWaterID, cExplorePlanLOSMultiplier,  0, 4.0 );
  595.       aiPlanAddUnitType(exploreWaterID, fishGatherer, 1, 1, 1);
  596.       aiPlanSetDesiredPriority(exploreWaterID, 90);
  597.       aiPlanSetActive(exploreWaterID);
  598.    }
  599.  
  600.     xsDisableSelf();
  601. }
  602.  
  603.  
  604. rule scout
  605.    active
  606. {
  607.    // just set up an explore plan
  608.    int exploreID = aiPlanCreate("Explore", cPlanExplore);
  609.    if(exploreID >= 0)
  610.    {
  611.       //aiPlanAddVariableFloat( exploreID, cExplorePlanLOSMultiplier, "LOS Multiplier", 1);
  612.       aiPlanSetVariableFloat( exploreID, cExplorePlanLOSMultiplier,  0, 4.0 );
  613.       aiPlanAddUnitType(exploreID, cUnitTypeScout, 1, 1, 1);
  614.       aiPlanSetDesiredPriority(exploreID, 90);
  615.       aiPlanSetActive(exploreID);
  616.    }
  617.  
  618.    xsDisableSelf();
  619. }